home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / xlib / xlib06 / xrletool.asm < prev    next >
Assembly Source File  |  1993-10-03  |  18KB  |  655 lines

  1. ;-----------------------------------------------------------------------
  2. ; MODULE XRLETOOL
  3. ;
  4. ; Hardware detection module
  5. ;
  6. ; Compile with Tasm.
  7. ; C callable.
  8. ;
  9. ;
  10. ; ****** XLIB - Mode X graphics library                ****************
  11. ; ******                                               ****************
  12. ; ****** Written By Themie Gouthas                     ****************
  13. ;
  14. ; egg@dstos3.dsto.gov.au
  15. ; teg@bart.dsto.gov.au
  16. ;-----------------------------------------------------------------------
  17.  
  18. COMMENT $
  19.  
  20. Firstly, please note that this module has been built from the ground up
  21. in a rush so although I'm confident all the functions work, I have'nt
  22. extensively checked them. If any should surface please let me know.
  23.  
  24.  
  25. This module implements a number of functions comprising an RLE encoding
  26. decoding system.
  27.  
  28. RLE stands for RUN LENGTH ENCODING. It is a quick simple data compression
  29. scheme which is commonly used for image data compression or compression
  30. of any data. Although not the most efficient system, it is fast, which is
  31. why it is used in image storage systems like PCX. This implementation is
  32. more efficient than the one used in PCX files because it uses 1 bit to
  33. identify a Run Length byte as opposed to two in PCX files, but more on this
  34. later.
  35.  
  36. This set of functions can be used to implement your own compressed image
  37. file format or for example compress game mapse for various levels etc.
  38. The uses are limited by your imagination.
  39.  
  40. I opted for trading off PCX RLE compatibility for the improved compression
  41. efficiency.
  42.  
  43. Here is how the data is un-compressed to give an idea of its structure.
  44.  
  45.  
  46. STEP 1 read a byte from the RLE compressed source buffer.
  47.  
  48. STEP 2 if has its high bit then the lower 7 bits represent the number of
  49.        times the next byte is to be repeated in the destination buffer.
  50.        if the count (lower 7 bits) is zero then
  51.       we have finished decoding goto STEP 5
  52.        else goto STEP 4
  53.  
  54. STEP 3 Read a data from the source buffer and copy it directly to the
  55.        destination buffer.
  56.        goto STEP 1
  57.  
  58. STEP 4 Read a data from the source buffer and copy it to the destination
  59.        buffer the number of times specified by step 2.
  60.        goto STEP 1
  61.  
  62. STEP 5 Stop, decoding done.
  63.  
  64. If the byte does not have the high bit set then the byte itself is transfered
  65.  to the destination buffer.
  66.  
  67. Data bytes that have the high bit already set and are unique in the input
  68.  stream are represented as a Run Length of 1 (ie 81 which includes high bit)
  69.  followed by the data byte.
  70.  
  71. If your original uncompressed data contains few consecutive bytes and most
  72. have high bit set (ie have values > 127) then your so called
  73. compressed data would require up to 2x the space of the uncompressed data,
  74. so be aware that the compression ratio is extremely variable depending on the
  75. type of data being compressed.
  76.  
  77. Apologies for this poor attempt at a description, but you can look up
  78. RLE in any good text. Alternatively, any text that describes the PCX file
  79. structure in any depth should have a section on RLE compression.
  80.  
  81.  
  82.  
  83. $
  84.  
  85. LOCALS
  86. .286
  87.  
  88. include model.inc
  89. include xrletool.inc
  90.  
  91.     .data
  92.  
  93. _RLE_last_buff_offs dw (0)
  94. RLEbuff db 2 dup (?)
  95.  
  96.     .code
  97.  
  98. ;****************************************************************
  99. ;*
  100. ;* NAME: x_buff_RLEncode
  101. ;*
  102. ;*
  103. ;* RLE Compresses a source buffer to a destination buffer and returns
  104. ;* the size of the resultant compressed data.
  105. ;*
  106. ;* C PROTOTYPE:
  107. ;*
  108. ;*  extern unsigned int x_buff_RLEncode(char far * source_buff,
  109. ;*           char far * dest_buff,unsigned int count);
  110. ;*
  111. ;* source_buff   - The buffer to compress
  112. ;* dest_buff     - The destination buffer
  113. ;* count         - The size of the source data in bytes
  114. ;*
  115. ;* WARNING: buffers must be pre allocated.
  116. ;*
  117. proc _x_buff_RLEncode
  118. ARG   src:dword,dest:dword,count:word
  119.     push bp
  120.     mov  bp,sp
  121.     push ds
  122.     push si
  123.     push di
  124.  
  125.     lds  si,[src]
  126.     les  di,[dest]
  127.     mov  dx,[count]
  128.  
  129.     push di
  130.  
  131.     lodsb              ; Load first byte into BL
  132.     mov  bl,al
  133.     xor  cx,cx         ; Set number characters packed to zero
  134.     cld                ; All moves are forward
  135.  
  136. @@RepeatByte:
  137.     lodsb           ; Get byte into AL
  138.     inc  cx            ; Increment compressed byte count
  139.     sub  dx,1          ; Decrement bytes left
  140.     je   @@LastByte    ; Finished when dx = 1
  141.     cmp  cx,7fh        ; Filled block yet
  142.     jne  @@NotFilled   ; Nope!
  143.  
  144.     or   cl,80h        ; Set bit to indicate value is repeat count
  145.     mov  es:[di],cl    ; store it
  146.     inc  di
  147.     xor  cx,cx         ; clear compressed byte count
  148.     mov  es:[di],bl    ; store byte to be repeated
  149.     inc  di
  150.  
  151. @@NotFilled:
  152.     cmp  al,bl         ; hase there been a byte transition ?
  153.     je   @@RepeatByte  ; No!
  154.  
  155.     cmp  cl,1          ; do we have a unique byte ?
  156.     jne  @@NotUnique   ; No
  157.  
  158.     test bl,80h        ; Can this byte be mistaken for repeat count
  159.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  160.  
  161. @@NotUnique:
  162.     or   cl,80h        ; Set bit to indicate value is repeat count
  163.     mov  es:[di],cl    ; store it
  164.     inc  di
  165. @@Unambiguous:
  166.     xor  cx,cx         ; clear compressed byte count
  167.     mov  es:[di],bl    ; store byte to be repeated
  168.     inc  di
  169.     mov  bl,al         ; move latest byte into bl
  170.     jmp  short @@RepeatByte
  171.  
  172. @@LastByte:
  173.     cmp  cl,1          ; Is this a unique byte
  174.     jne  @@FinalCount  ; No
  175.  
  176.     test bl,80h        ; Can this byte be mistaken for repeat count
  177.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  178.  
  179. @@FinalCount:              ; Output the repeat count
  180.     or   cl,80h
  181.     mov  al,cl
  182.     stosb
  183.  
  184. @@FinalByte:
  185.     mov  al,bl
  186.     stosb
  187.  
  188.     mov  al,80h       ; store terminating null length
  189.     stosb
  190.  
  191.         ; Calculate encoded length of buffer
  192.  
  193.     mov  ax,di
  194.     pop  di
  195.     sub  ax,di
  196.  
  197.     pop  di
  198.     pop  si
  199.     pop  ds
  200.     pop  bp
  201.     ret
  202. _x_buff_RLEncode endp
  203.  
  204.  
  205.  
  206. ;****************************************************************
  207. ;*
  208. ;* NAME: x_buff_RLE_size
  209. ;*
  210. ;*
  211. ;* Returns the size the input data would compress to.
  212. ;*
  213. ;* C PROTOTYPE:
  214. ;*
  215. ;*  extern unsigned int x_buff_RLE_size(char far * source_buff,
  216. ;*           unsigned int count);
  217. ;*
  218. ;* source_buff   - The uncompressed data buffer
  219. ;* count         - The size of the source data in bytes
  220. ;*
  221. ;*
  222. proc _x_buff_RLE_size
  223. ARG   src:dword,count:word
  224.     push bp
  225.     mov  bp,sp
  226.     push ds
  227.     push si
  228.     push di
  229.  
  230.     lds  si,[src]
  231.     mov  dx,[count]
  232.  
  233.     xor  di,di
  234.  
  235.     lodsb              ; Load first byte into BL
  236.     mov  bl,al
  237.     xor  cx,cx         ; Set number characters packed to zero
  238.     cld                ; All moves are forward
  239.  
  240. @@RepeatByte:
  241.     lodsb           ; Get byte into AL
  242.     inc  cx            ; Increment compressed byte count
  243.     sub  dx,1          ; Decrement bytes left
  244.     je   @@LastByte    ; Finished when dx = 1
  245.     cmp  cx,7fh        ; Filled block yet
  246.     jne  @@NotFilled   ; Nope!
  247.  
  248.     add  di,2          ; RL/BYTE pair stub
  249.  
  250. @@NotFilled:
  251.     cmp  al,bl         ; hase there been a byte transition ?
  252.     je   @@RepeatByte  ; No!
  253.  
  254.     cmp  cl,1          ; do we have a unique byte ?
  255.     jne  @@NotUnique   ; No
  256.  
  257.     test bl,80h        ; Can this byte be mistaken for repeat count
  258.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  259.  
  260. @@NotUnique:
  261.     inc  di            ; RL stub
  262.  
  263. @@Unambiguous:
  264.     xor  cx,cx         ; clear compressed byte count
  265.     inc  di            ; BYTE stub
  266.     mov  bl,al         ; move latest byte into bl
  267.     jmp  short @@RepeatByte
  268.  
  269. @@LastByte:
  270.     cmp  cl,1          ; Is this a unique byte
  271.     jne  @@FinalCount  ; No
  272.  
  273.     test bl,80h        ; Can this byte be mistaken for repeat count
  274.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  275.  
  276. @@FinalCount:              ; Output the repeat count
  277.     inc  di            ; RL stub
  278.  
  279. @@FinalByte:
  280.     inc  di            ; BYTE stub
  281.     inc  di            ; RL stub - Account for termiating null
  282.     mov  ax,di
  283.  
  284.     pop  di
  285.     pop  si
  286.     pop  ds
  287.     pop  bp
  288.     ret
  289. _x_buff_RLE_size endp
  290.  
  291. ;****************************************************************
  292. ;*
  293. ;* NAME: x_buff_RLDecode
  294. ;*
  295. ;*
  296. ;* Expands an RLE compresses source buffer to a destination buffer.
  297. ;* returns the size of the resultant uncompressed data.
  298. ;*
  299. ;* C PROTOTYPE:
  300. ;*
  301. ;*  extern unsigned int x_buff_RLDecode(char far * source_buff,
  302. ;*           char far * dest_buff);
  303. ;*
  304. ;* source_buff   - The buffer to compress
  305. ;* dest_buff     - The destination buffer
  306. ;*
  307. ;* WARNING: buffers must be pre allocated.
  308. ;*
  309. proc _x_buff_RLDecode
  310. ARG   src:dword,dest:dword
  311. LOCAL si_ini:word=LocalStk
  312.     push bp
  313.     mov  bp,sp
  314.         sub  sp,LocalStk
  315.     push ds
  316.     push si
  317.     push di
  318.  
  319.     mov  dx,-1        ; zero output data buffer size - 1 (compensate for
  320.               ; terminating null RL)
  321.     xor  cx,cx        ; clear CX
  322.     cld               ; Move forward
  323.  
  324.     lds  si,[src]     ; point ds:si -> RLE source
  325.     les  di,[dest]    ; point es:di -> uncompressed buffer
  326.         mov  [si_ini],si
  327.  
  328. @@UnpackLoop:
  329.     lodsb             ; load a byte into AL
  330.     cmp  al,80h       ; is it terminating null RL code
  331.     je   @@done       ; if so jump
  332.  
  333.     test al,80h       ; is AL a RL code (is high bit set ?)
  334.     jz   @@NoRepeats  ; if not the no RL encoding for this byte, jump
  335.  
  336.     mov  cl,al        ; set CL to RL (run length) taking care
  337.     xor  cl,80h       ; to remove the bit identifying it as a RL
  338.         add  dx,cx        ; increment buffer size
  339.  
  340.     lodsb             ; get the next byte which should be a data byte
  341.  
  342.     shr  cx,1         ; divide RL by 2 to use word stos
  343.     jcxz @@NoRepeats  ; result is zero, jump
  344.  
  345.     mov  ah,al        ; copy data byte to AH since going to use stosw
  346.     rep  stosw        ; copy AX to outbut buffer RL times
  347.     jnb  @@UnpackLoop ; when we shifted the RL if we had a carry =>
  348.               ; we had an odd number of repeats so store the
  349.               ; last BYTE if carry was set otherwise jump
  350.         stosb             ; store AL in destination buffer
  351.         jmp  short @@UnpackLoop
  352.  
  353. @@NoRepeats:
  354.     inc  dx           ; increment buffer size
  355.     stosb             ; store AL in destination buffer
  356.         jmp  short @@UnpackLoop
  357.  
  358. @@done:
  359.  
  360.         mov  bx,si
  361.         sub  bx,[si_ini]
  362.     mov  ax,dx
  363.     pop  di
  364.     pop  si
  365.     pop  ds
  366.         mov  [_RLE_last_buff_offs],bx
  367.         mov  sp,bp
  368.     pop  bp
  369.     ret
  370. _x_buff_RLDecode endp
  371.  
  372. ;==========================================================================
  373. ;==========================================================================
  374. ; RLEncode to file / RLDecode from file
  375. ; WARNING the following functions are *MUCH* slower than the above
  376. ; Its best to use the above functions with intermediate buffers where
  377. ; disk i/o is concearned... See demo 4
  378. ;==========================================================================
  379. ;==========================================================================
  380.  
  381. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  382. ;
  383. ; put_cx
  384. ;
  385. ;   Local utility proc for x_file_RLEncode - write cx to file
  386. ;
  387. ; Entry:
  388. ;       es:dx -> output buffer
  389. ;       cx = word to write
  390. ;
  391. ;
  392. put_cx proc near
  393.     push ds             ; preserve critical registers
  394.     push ax
  395.     push bx
  396.     mov  ax,ds          ; set up DS to output buffers segment
  397.     mov  ds,ax
  398.     mov  word ptr [RLEbuff],cx ; copy CX to output buffer
  399.     mov  ah,40h         ; select "write to file or device" DOS service
  400.     mov  bx,[handle]    ; select handle of file to write
  401.     mov  cx,2           ; sending 2 bytes
  402.     int  21h        ; call DOS service
  403.     pop  bx             ; recover registers
  404.     pop  ax
  405.     pop  ds
  406.     ret
  407. put_cx endp
  408.  
  409. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  410. ;
  411. ; put_cx
  412. ;
  413. ;   Local utility proc for x_file_RLEncode - write cx to file
  414. ;
  415. ; Entry:
  416. ;       es:dx -> output buffer
  417. ;       cx = word to write
  418. ;
  419. ;
  420. put_cl proc near
  421.     push ds             ; preserve critical registers
  422.     push ax
  423.     push bx
  424.     mov  ax,ds          ; set up DS to output buffers segment
  425.     mov  ds,ax
  426.     mov  byte ptr [RLEbuff],cl
  427.     mov  ah,40h         ; select "write to file or device" DOS service
  428.     mov  bx,[handle]    ; select handle of file to write
  429.     mov  cx,1           ; sending 1 byte
  430.     int  21h        ; call DOS service
  431.     pop  bx             ; recover registers
  432.     pop  ax
  433.     pop  ds
  434.     ret
  435. put_cl endp
  436.  
  437.  
  438. ;****************************************************************
  439. ;*
  440. ;* NAME: x_file_RLEncode
  441. ;*
  442. ;*
  443. ;* RLE Compresses a source buffer to an output file returning
  444. ;* the size of the resultant compressed data or 0 if it fails.
  445. ;*
  446. ;* C PROTOTYPE:
  447. ;*
  448. ;*  extern unsigned int x_file_RLEncode(int handle,
  449. ;*           char far * source_buff,unsigned int count);
  450. ;*
  451. ;* source_buff   - The buffer to compress
  452. ;* handle        - The file handler
  453. ;* count         - The size of the source data in bytes
  454. ;*
  455. ;*
  456. proc _x_file_RLEncode
  457. ARG   handle:word,src:dword,count:word
  458. LOCAL filesize:word=LocalStk
  459.     push bp
  460.     mov  bp,sp
  461.     sub  sp,LocalStk
  462.     push ds
  463.     push si
  464.     push di
  465.  
  466.     mov  [filesize],0
  467.     mov  dx,offset [RLEbuff]
  468.     mov  ax,ds
  469.     mov  es,ax
  470.     lds  si,[src]
  471.     mov  di,[count]
  472.  
  473.     lodsb              ; Load first byte into BL
  474.     mov  bl,al
  475.     xor  cx,cx         ; Set number characters packed to zero
  476.     cld                ; All moves are forward
  477.  
  478. @@RepeatByte:
  479.     lodsb           ; Get byte into AL
  480.     inc  cx            ; Increment compressed byte count
  481.     sub  di,1          ; Decrement bytes left
  482.     je   @@LastByte    ; Finished when di = 1
  483.     cmp  cx,7fh        ; Filled block yet
  484.     jne  @@NotFilled   ; Nope!
  485.  
  486.     or   cl,80h        ; Set bit to indicate value is repeat count
  487.     mov  ch,bl
  488.     add  [filesize],2
  489.     call put_cx
  490.     jb   @@FileError   ; if carry set then file I/O error
  491.     xor  cx,cx         ; clear compressed byte count
  492.  
  493. @@NotFilled:
  494.     cmp  al,bl         ; hase there been a byte transition ?
  495.     je   @@RepeatByte  ; No!
  496.  
  497.     cmp  cl,1          ; do we have a unique byte ?
  498.     jne  @@NotUnique   ; No
  499.  
  500.     test bl,80h        ; Can this byte be mistaken for repeat count
  501.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  502.  
  503. @@NotUnique:
  504.     or   cl,80h        ; Set bit to indicate value is repeat count
  505.     inc  [filesize]
  506.     call put_cl        ; store it
  507.         jb   @@FileError   ; if carry set then file I/O error
  508. @@Unambiguous:
  509.  
  510.     mov  cl,bl         ; store byte to be repeated
  511.         inc  [filesize]
  512.     call put_cl
  513.         jb   @@FileError   ; if carry set then file I/O error
  514.     mov  bl,al         ; move latest byte into bl
  515.         xor  cx,cx         ; clear compressed byte count
  516.     jmp  short @@RepeatByte
  517.  
  518. @@FileError:
  519.     mov  ax,0
  520.     jmp  short @@exit
  521.  
  522. @@LastByte:
  523.     cmp  cl,1          ; Is this a unique byte
  524.     jne  @@FinalCount  ; No
  525.  
  526.     test bl,80h        ; Can this byte be mistaken for repeat count
  527.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  528.  
  529. @@FinalCount:              ; Output the repeat count
  530.     or   cl,80h
  531.         inc  [filesize]
  532.     call put_cl
  533.     jb   @@FileError   ; if carry set then file I/O error
  534.  
  535. @@FinalByte:
  536.     mov  cl,bl
  537.     mov  ch,80h
  538.     add  [filesize],2
  539.     call put_cx        ; store terminating null length
  540.     jb   @@FileError   ; if carry set then file I/O error
  541.  
  542.     mov  ax,[filesize]
  543.     jmp  short @@exit
  544.  
  545. @@exit:
  546.     pop  di
  547.     pop  si
  548.     pop  ds
  549.     mov  sp,bp
  550.     pop  bp
  551.     ret
  552. _x_file_RLEncode endp
  553.  
  554.  
  555.  
  556.  
  557. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  558. ;
  559. ; GET_BYTE
  560. ;
  561. ;   macro to read a byte from the input file into al
  562. ;
  563. GET_BYTE macro
  564.     push bx
  565.     mov  ah,3fh         ; select "read from file or device" DOS service
  566.     mov  bx,[handle]    ; Select handle of file to close
  567.     mov  cx,1           ; Want to read 1 byte
  568.     int  21h            ; call DOS service
  569.     pop  bx
  570.     jb   @@FileError    ; failed if carry flag set
  571.     mov  al,[RLEbuff]
  572.     endm
  573.  
  574.  
  575. ;****************************************************************
  576. ;*
  577. ;* NAME: x_file_RLDecode
  578. ;*
  579. ;*
  580. ;* Expands an RLE compresses file to a destination RAM buffer.
  581. ;* returns the size of the resultant uncompressed data.
  582. ;*
  583. ;* C PROTOTYPE:
  584. ;*
  585. ;*  extern unsigned int x_buff_RLDecode(int handle,
  586. ;*           char far * dest_buff);
  587. ;*
  588. ;* handle        - Input file handle
  589. ;* dest_buff     - The destination buffer
  590. ;*
  591. ;*
  592. proc _x_file_RLDecode
  593. ARG   handle:word,dest:dword
  594.     push bp
  595.     mov  bp,sp
  596.     push si
  597.     push di
  598.  
  599.  
  600.     mov  bx,-1        ; zero output data buffer size - 1 (compensate for
  601.               ; terminating null RL)
  602.     mov  dx,offset [RLEbuff] ; setup DS:DX -> RLEBuffer
  603.         xor  cx,cx        ; clear CX
  604.     cld               ; Move forward
  605.  
  606.     les  di,[dest]    ; point es:di -> uncompressed buffer
  607.  
  608. @@UnpackLoop:
  609.  
  610.     GET_BYTE      ; Load a byte from file into AL
  611.  
  612.     cmp  al,80h       ; is it terminating null RL code
  613.     je   @@done       ; if so jump
  614.  
  615.     test al,80h       ; is AL a RL code (is high bit set ?)
  616.     jz   @@NoRepeats  ; if not the no RL encoding for this byte, jump
  617.  
  618.     mov  cl,al        ; set CL to RL (run length) taking care
  619.     xor  cl,80h       ; to remove the bit identifying it as a RL
  620.     add  bx,cx        ; increment buffer size
  621.     mov  si,cx        ; save the CX value
  622.     GET_BYTE          ; Load a byte from file into AL
  623.     mov  cx,si        ; restore CX value
  624.         shr  cx,1         ; divide RL by 2 to use word stos
  625.     jcxz @@NoRepeats  ; result is zero, jump
  626.  
  627.     mov  ah,al        ; copy data byte to AH since going to use stosw
  628.     rep  stosw        ; copy AX to outbut buffer RL times
  629.     jnb  @@UnpackLoop ; when we shifted the RL if we had a carry =>
  630.               ; we had an odd number of repeats so store the
  631.               ; last BYTE if carry was set otherwise jump
  632.         stosb             ; store AL in destination buffer
  633.         jmp  short @@UnpackLoop
  634.  
  635. @@NoRepeats:
  636.     inc  bx
  637.     stosb             ; store AL in destination buffer
  638.         jmp  short @@UnpackLoop
  639.  
  640. @@FileError:
  641.     mov  ax,0
  642.     jmp  short @@exit
  643.  
  644. @@done:
  645.     mov  ax,bx
  646. @@exit:
  647.     pop  di
  648.     pop  si
  649.     pop  bp
  650.     ret
  651. _x_file_RLDecode endp
  652.  
  653.     end
  654.  
  655.